<?php

abstract class Resource_Backend_Utils 
{
    
    /**
    * @desc Return positions list that can be placed under the specified parent. 
    * 
    * 
    * @param string     $menu
    * @param integer    $parent [declared parent]
    * @param integer    $resource
    * @return array
    */
    static public function positions($menu, $parent, $resource) 
    {
        $query = '
            SELECT 
                   COUNT(`i`.`resource_id`) 
              FROM 
                   `system_navigation_item` `i`, `system_navigation` `n` 
             WHERE 
                   `parent_id` = ' . $parent . '
               AND 
                   %s 
             ';
        $elements_num = database::fetchOne(sprintf($query, self::_query_menu_part($menu)));
        
        // check whether declared parent is the same as specified resource has, 
        // otherwise it means that resource is moved within the tree, so place 
        // additional position for it 
        // OR 
        // current resource is 0 (it means that we add a new resource), so also 
        // place additional position 
        $query = '
            SELECT 
                   `i`.`parent_id`
              FROM 
                   `system_navigation_item` `i`, `system_navigation` `n` 
             WHERE 
                   `i`.`resource_id` = ' . $resource . '
            ';
        if (database::fetchOne($query) != $parent || $resource < 1) { 
            $elements_num += 1; 
        }
        
        $positions = range(1, $elements_num);
        return array_combine($positions, $positions);
    }
    
    /**
    * @desc Return element position from specified menu. 
    * 
    * @param string $menu
    * @param integer
    * @param integer
    * 
    * @return array
    */
    static public function position($menu, $parent_src, $resource) 
    {
        if ($resource > 0) {
            $query = '
                SELECT 
                       `i`.`parent_id` `parent_dst`, 
                       `i`.`position` `position`
                  FROM 
                       `system_navigation_item` `i`, `system_navigation` `n` 
                 WHERE 
                       `resource_id` = ' . $resource . '
                   AND 
                       %s 
                 ';
            
            $positions = database::fetchRow(sprintf($query, self::_query_menu_part($menu)));
            
            if ($positions) {
                extract($positions);
                return $parent_src == $parent_dst ? $position : 0;
            } else {
                array();
            }
        } else {
            return self::position_max($menu, $parent_src) + 1;
        }
    }
    
    /**
    * @desc Return max position of any element or if parent specified then under
    * this parent. 
    * 
    * @param string $menu
    * @param integer $parent= null
    * 
    * @return integer
    */
    static public function position_max($menu, $parent = null) 
    {
        $query = '
            SELECT 
                   MAX(`i`.`position`)
              FROM 
                   `system_navigation_item` `i`, `system_navigation` `n` 
             WHERE 
            ';
        if (!is_null($parent)) {
            $query .= '
                      `i`.`parent_id` = ' . $parent . ' 
                  AND 
                ';
        }
        $query .= '
            %s
            ';
        return (int)database::fetchOne(sprintf($query, self::_query_menu_part($menu)));
    }
    
    /**
    * @desc Current branch can not be moved to itself and in any of its children.
    * 
    * @param string $menu
    */
    static public function parents($menu) 
    {
        $parents = Kernel_Util_Tree::non_children(
            Kernel::factory('Kernel', 'Resource')->menu($menu), 
            Resource_Backend::active()
            );

        return self::convertToList($parents);
    }
    
    /**
    * @desc Return parent of the current resource. 
    * 
    * @param string $menu
    */
    static public function parent($menu) 
    {
        foreach (Kernel::factory('Kernel', 'Resource')->menu($menu) as $entry) {
            if (Resource_Backend::active() == $entry['id']) {
                return $entry['parent_id'];
            }
        }
    }
    
    /**
    * @desc Return menu ID by its name
    * 
    * @param string     $name
    * @return integer
    */
    static public function menuId($name) 
    {
        static $menus = array();
        
        if (!array_key_exists($name, $menus)) {
            $query = '
                SELECT 
                       `id` 
                  FROM 
                       `system_navigation` 
                 WHERE 
                       `name` = "' . database::escape($name) . '"
                ';
            $menus[$name] = (int)database::fetchOne($query);
        }
        
        return $menus[$name];
    }
    
    /**
    * Return list of modules available to attach to resources. 
    * 
    * @return array
    */
    static public function availableModules() 
    {
        return $modules = array
            (
                'static' => __('STATIC'), 
            );
    }
    
    static public function options($module) 
    {
        if (class_exists($class = ucfirst($module) . '_Backend')) {
            if (!in_array('Resource_Backend_Interface', class_implements($class))) {
                trigger_error($class . ' must implement interface Resource_Backend_Interface', E_USER_ERROR);
            }
            
            return (array)call_user_func(array($class, __FUNCTION__));
        }
        
        return array();
    }
    
    static public function getModuleResources($module) 
    {
        $cach = array();
        
        if (empty($cach)) {
            $query = '
                SELECT 
                       `n`.`name` `menu`, 
                       `r`.`id`, 
                       `r`.`name` 
                  FROM 
                       `system_resource` `r`, 
                       `system_navigation_item` `i`, 
                       `system_navigation` `n`
                 WHERE 
                       `r`.`module` = "' . database::escape($module) . '" 
                   AND 
                       `i`.`resource_id` = `r`.`id` 
                   AND 
                       `i`.`menu_id` = `n`.`id`
              ORDER BY 
                       `n`.`id`, `r`.`name`
                   ASC 
                ';
            
            $query_2 = '
                SELECT 
                       "hidden" `menu`, 
                       `r`.`id`, 
                       `r`.`url` `name`
                  FROM 
                       `system_resource` `r`
                 WHERE 
                       `r`.`module` = "' . database::escape($module) . '" 
                   AND 
                       `r`.`name` = ""
              ORDER BY 
                       `r`.`url`
                   ASC 
                ';
            
            $cach = array_merge(database::fetchAll($query), database::fetchAll($query_2));
        }
        
        return $cach;
    }
    
    /**
    * List of the frame templates.
    * 
    * @return array
    */
    static public function frameTemplates() 
    {
        return array(
            ''     => __('DEFAULT'), 
            'main' => __('MAIN'), 
            );
    }
    
    /**
    * List of the inner templates.
    * 
    * @return array
    */
    static public function innerTemplates() 
    {
        return array();
    }
    
    /**
    * @desc Make list from tree entries padding with $symbol $pad times. 
    * 
    * 
    * @param array      $set
    * @param array      &$list
    * @param integer    $pad
    * @param string     $symbol
    */
    static public function convertToList($set, $pad = 2, $symbol = '&nbsp;') 
    {
        $list = array();
        
        self::_list_recursive($set, $list, (int)$pad, $symbol, $inc = 1);
        
        return $list;
    }
    
    /**
    * @desc Apply padding to the value recursively. 
    * 
    * @param array  $set
    * @param array  &$list
    * @param integer $pad
    * @param string $symbol 
    * @param integer $inc
    */
    static private function _list_recursive($set, &$list, $pad, $symbol, $inc) 
    {
        $padding = str_pad('', strlen($symbol)*($pad*$inc), $symbol, STR_PAD_LEFT);
        
        foreach ($set as $node) {
            $list[$node['id']] = $padding . $node['name'];
            
            if (!empty($node['children'])) {
                self::_list_recursive($node['children'], &$list, $pad, $symbol, ++$inc);
            }
            
        }
    }
    
    /**
    * @desc Return SQL part of menu definition. 
    * 
    * @param string 
    * @return string
    */
    static private function _query_menu_part($name) 
    {
        return '
                   `n`.`name` = "' . database::escape($name) . '" 
               AND 
                   `i`.`menu_id` = `n`.`id`
            ';
    }
    
}